using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Text;
using System.Text.RegularExpressions;
using System.Diagnostics;

namespace My.IdlConverter.Core.Parsers
{
    public class MethodParser : ParserBase
    {
        public static readonly string VIRTUAL_PATTERN = @".*virtual";
        public static readonly string CONST_PATTERN = @"\).*const";

        public MethodParser()
            : base()
        {
        }

        ~MethodParser() { }

        public override object Parse(string target)
        {
            DeleteVirtual(ref target);
            Method method = ParseMethod(target);
            Success = ( method != null );
            return method;
        }

        private void DeleteVirtual(ref string method)
        {
            try
            {
                Regex reg = new Regex(VIRTUAL_PATTERN);
                Match match = reg.Match(method);
                Debug.Assert(match.Success == true);
                method.Trim(' ', '\t');
                string value = match.Value;
                method = method.Substring(value.Length);
            }
            catch (Exception e)
            {
                Debug.Assert(false);
                Console.WriteLine(e.Message);
            }
        }

        private Method ParseMethod(string method)
        {
            int spacePos = method.IndexOf('(');
            string prefix = method.Substring(0, spacePos);
            prefix.Trim();
            spacePos = prefix.LastIndexOf(' ');
            string typeString = prefix.Substring(0, spacePos);
            typeString = typeString.Trim();
            string methodName = prefix.Substring(spacePos);
            methodName = methodName.Trim();

            Types.TypeTranslator typeTranslator = new Types.TypeTranslator(typeString);
            Types.IType returnType = typeTranslator.Translate();
            Method methodObj = new Method(returnType, methodName, ParseFunctionConst(method));
            returnType.Parent = methodObj;

            ParseParameters(methodObj,method);

            return methodObj;
        }

        private string ParseFunctionConst(string method)
        {
            Regex reg = new Regex(CONST_PATTERN);
            if (reg.IsMatch(method))
                return "const";
            else
                return "";
        }

        private void ParseParameters(Method methodObj,string method)
        {
            int begPos = method.IndexOf('(');
            int endPos = method.LastIndexOf(')');
            int count = endPos - begPos - 1;
            if (count <= 1)
            {
                return;
            }
            method = method.Substring(begPos + 1, count);

            //<source,substitution>
            IParser paramParse = new ParameterParser();

            if (Types.TypeRecognizer.ExistStlTypes(method))
            {
                StringCollection stlTypes = Types.TypeRecognizer.GetStlTypeEntries(method);
                foreach (string nextStlType in stlTypes)
                {
                    Parameter paramObj = paramParse.Parse(nextStlType) as Parameter;
                    Debug.Assert(paramObj != null);
                    if (paramParse.Success)
                    {
                        methodObj.Parameters.Add(paramObj);
                        paramObj.Parent = methodObj;
                        int pos = method.IndexOf(nextStlType);
                        method = method.Remove(pos, nextStlType.Length);
                    }
                    else
                    {
                        Debug.Assert(false);
                    }
                }
            }
            string[] parameters = method.Split(new char[] { ','},StringSplitOptions.RemoveEmptyEntries);
            foreach (string nextParam in parameters)
            {
                string paramString = nextParam.Trim();
                if (paramString.Length > 0)
                {
                    Parameter param = paramParse.Parse(paramString) as Parameter;
                    param.Parent = methodObj;
                    Debug.Assert(param != null);
                    if (paramParse.Success)
                        methodObj.Parameters.Add(param);
                    else
                    {
                        Debug.Assert(false);
                    }
                }
            }
        }
    }
}
